package com.unitd.logistics.comm.plugins.module.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.unitd.logistics.comm.spring.beanvalidator.BeanValidatorUtils;
import com.unitd.logistics.comm.spring.editor.CustomDateEditor;
import com.unitd.logistics.comm.spring.editor.StringEscapeEditor;
import com.unitd.logistics.comm.utils.StringUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.beans.PropertyEditorSupport;
import java.util.*;

/**
 * 前段控制器基类
 *
 * @author Hudan
 * @version 1.0
 * @filename BaseController.java
 * @copyright www.pactera.com
 * @date 2019-01-23
 */
public class BaseController {

	@Autowired
	protected HttpServletRequest request;
	@Autowired
	protected HttpServletResponse response;
	@Autowired
	protected HttpSession session;
	@Autowired
	protected ServletContext application;

	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;

	/**
	 * 初始化前端请求数据的绑定
	 *
	 * @param binder  绑定器
	 * @param request web请求
	 */
	@InitBinder
	public void initBinder(WebDataBinder binder, WebRequest request) {
		// 自动转换日期类型的字段格式
		binder.registerCustomEditor(Date.class, new CustomDateEditor(true));
		// 防止XSS攻击
		binder.registerCustomEditor(String.class, new StringEscapeEditor(true, false));
		// String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
			}

			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
	}

	/**
	 * 获取请求对象
	 *
	 * @return http请求对象
	 */
	protected HttpServletRequest getRequest() {
		return request;
	}

	/**
	 * 获取响应对象
	 *
	 * @return http响应对象
	 */
	protected HttpServletResponse getResponse() {
		return response;
	}

	/**
	 * 重定向到指定URL
	 *
	 * @param url 需要重定向的URL
	 * @return 需要重定向的URL
	 */
	protected String redirectTo(String url) {
		return "redirect:" + url;
	}

	/**
	 * 获取前端我请求中的分页数据信息, 并将当前页数和每页记录数存入Map对象, 方便controller类使用
	 *
	 * @return 分页信息
	 */
	protected Map<String, Integer> getPageMap() {
		return this.getPageMap(10);
	}

	/**
	 * 获取前端我请求中的分页数据信息, 并将当前页数和每页记录数存入Map对象, 方便controller类使用
	 *
	 * @param size 每页记录数
	 * @return 分页对象信息
	 */
	protected Map<String, Integer> getPageMap(int size) {
		Map<String, Integer> pageMap = new HashMap<>(2);

		int pageSize = size;
		int pageNo = 1;
		// 每页大小
		if (this.request.getParameter("_size") != null) {
			pageSize = Integer.parseInt(this.request.getParameter("_size"));
		}

		// 需要显示的当前页数
		if (this.request.getParameter("_index") != null) {
			pageNo = Integer.parseInt(this.request.getParameter("_index"));
		}

		pageMap.put("pageNo", (pageNo / pageSize) + 1);
		pageMap.put("pageSize", pageSize);
		return pageMap;
	}

	/**
	 * 将需要展示的数据以json格式展示
	 *
	 * @param object 需要展示的数据对象
	 * @return json串
	 */
	protected String toJson(Object object) {
		return JSON.toJSONString(object, SerializerFeature.BrowserCompatible);
	}

	/**
	 * 忽略错误的属性
	 *
	 * @param object 需要展示的数据对象
	 * @return json串
	 */
	protected String toJsonIgnoreErrGetter(Object object) {
		return JSON.toJSONString(object, new SerializerFeature[]{SerializerFeature.IgnoreErrorGetter});
	}

	/**
	 * 将需要展示的数据按照指定的格式, 格式化为json格式展示
	 *
	 * @param object 需要展示的数据对象
	 * @param format 格式器
	 * @return json串
	 */
	protected String toJson(Object object, String format) {
		return format == null ? this.toJson(object) : JSON.toJSONStringWithDateFormat(object, format, new SerializerFeature[]{SerializerFeature.WriteDateUseDateFormat});
	}

	/**
	 * 判断数据库操作是否成功
	 *
	 * @param result 数据库操作返回影响条数
	 * @return boolean
	 */
	public static boolean toBool(Integer result) {
		return null != result && result >= 1;
	}

	/**
	 * 判断是否为合法的视图地址
	 *
	 * @param modelAndView spring 视图对象
	 * @return boolean
	 */
	protected boolean isLegalView(ModelAndView modelAndView) {
		boolean legal = false;
		if (modelAndView != null) {
			String viewUrl = modelAndView.getViewName();
			if (viewUrl != null && viewUrl.contains("redirect:")) {
				legal = false;
			} else {
				legal = true;
			}
		}
		return legal;
	}

	/**
	 * 服务端参数有效性验证
	 *
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected String beanValidator(Object object, Class<?>... groups) {
		try {
			BeanValidatorUtils.validateWithException(validator, object, groups);
		} catch (ConstraintViolationException ex) {
			List<String> list = BeanValidatorUtils.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			return getMessageData(list.toArray(new String[]{}));
		}
		return null;
	}

	/**
	 * 根据request 获取前端数据集map
	 *
	 * @return Map
	 */
	public static Map<String, Object> getRequestValue(HttpServletRequest request, String prefix) {
		Map<String, Object> mInfo = new HashMap<>();
		if (null != request) {
			Iterator<String> it = request.getParameterMap().keySet().iterator();
			while (it.hasNext()) {
				String keyName = it.next();
				if (StringUtils.isNull(prefix) || keyName.startsWith(prefix)) {
					mInfo.put(keyName, request.getParameter(keyName));
				}
			}
		}
		return mInfo;
	}

	/**
	 * 添加Model消息
	 *
	 * @param messages 错误消息
	 */
	protected String getMessageData(String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages) {
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		return sb.toString();
	}
}